#include "module_frame.hh"

// HTTP callback type
enum class HttpCbType {
    HTTP_CB_SERVER = 1, // Callback for HTTP server
    HTTP_CB_CLIENT, // Callback for HTTP client
};

using namespace khttp;

// Callback for khttp
class InternalHttpCallback : public HttpCallback {
    HttpCbType type_; // Callback type
    HttpMethod cb_; // User callback
    ModuleFrame* frame_; // Module framework pointer
    bool received_; // Did got entire message
                    // get callback type string
    inline const std::string& getTypeString() {
        static std::string typeString[] = {"Server", "Client"};
        return typeString[static_cast<std::size_t>(type_)];
    }

public:
    InternalHttpCallback(HttpCbType type, HttpMethod cb, ModuleFrame* frame)
        : type_(type), cb_(cb), frame_(frame), received_(false) {
    }

    virtual ~InternalHttpCallback() {}

    virtual void onTimeout(HttpRequest* request) override {
        if (received_) {
            return;
        }
        try {
            if (cb_) {
                cb_(*request, HttpResult::HTTP_EVENT_TIMEOUT, 0);
            }
        } catch (std::exception& e) {
            errorlog << getTypeString() << ", Http exception in 'onTimeout':" << e.what() << ", request:"
                << request->debugString() << endlog;
        }
    }

    virtual void onError(HttpRequest* request, int32_t error) override {
        try {
            if (cb_) {
                cb_(*request, HttpResult::HTTP_EVENT_ERROR, error);
            }
        } catch (std::exception& e) {
            errorlog << getTypeString() << ", Http exception in 'onError':" << e.what() << ", request:"
                << request->debugString() << endlog;
        }
    }

    virtual void onClose(HttpRequest*) override {
        if (type_ == HttpCbType::HTTP_CB_CLIENT) {
            frame_->addHttpDeadCb(this);
        }
    }

    virtual bool onMessage(HttpRequest* request) override {
        try {
            if (type_ == HttpCbType::HTTP_CB_CLIENT) {
                received_ = true;
            }
            if (cb_) {
                cb_(*request, HttpResult::HTTP_EVENT_MESSAGE, 200);
            }
        } catch (std::exception& e) {
            errorlog << getTypeString() << ", Http exception in 'onMessage':" << e.what() << ", request:"
                << request->debugString() << endlog;
        }
        return true;
    }
};
